﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Processing;
using SixLabors.ImageSharp.Processing.Processors.Transforms;
using System.Collections;

namespace MyWatermark
{
    #region 抗噪测试
    public static class NoiseTestTools
    {
        // 添加高斯噪声
        public static byte[] AddGaussianNoise(byte[] imageData, double sigma)
        {
            var rand = new Random(WatermarkCore.RandomSeed);
            using var img = Image.Load<Bgra32>(imageData);

            img.ProcessPixelRows(accessor =>
            {
                for (int y = 0; y < accessor.Height; y++)
                {
                    var row = accessor.GetRowSpan(y);
                    for (int x = 0; x < row.Length; x++)
                    {
                        // 对每个颜色通道添加噪声
                        double noise = rand.NextGaussian(0, sigma);
                        row[x].R = Clamp(row[x].R + noise);
                        row[x].G = Clamp(row[x].G + noise);
                        row[x].B = Clamp(row[x].B + noise);
                    }
                }
            });

            return GetImageBytes(img);
        }

        // JPEG压缩测试
        public static byte[] AddJpegCompression(byte[] imageData, int quality)
        {
            using var img = Image.Load<Bgra32>(imageData);
            using var ms = new MemoryStream();
            img.SaveAsJpeg(ms, new JpegEncoder { Quality = quality });
            return ms.ToArray();
        }

        private static byte Clamp(double value) => (byte)Math.Clamp(value, 0, 255);

        public static byte[] GetImageBytes(Image<Bgra32> img)
        {
            using var ms = new MemoryStream();
            img.SaveAsPng(ms);
            return ms.ToArray();
        }
    }

    // Random扩展方法
    public static class RandomExtensions
    {
        public static double NextGaussian(this Random rand, double mean, double stdDev)
        {
            double u1 = 1.0 - rand.NextDouble();
            double u2 = 1.0 - rand.NextDouble();
            double randStdNormal = Math.Sqrt(-2.0 * Math.Log(u1)) * Math.Sin(2.0 * Math.PI * u2);
            return mean + stdDev * randStdNormal;
        }
    }


    #endregion


    #region 抗几何攻击测试
    public static class GeometricAttackTools
    {
        // 旋转攻击
        public static byte[] ApplyRotation(byte[] imageData, float degrees)
        {
            using var img = Image.Load<Bgra32>(imageData);
            img.Mutate(x => x.Rotate(degrees));
            return GetImageBytes(img);
        }

        // 裁切攻击（中心裁切）
        public static byte[] ApplyCenterCrop(byte[] imageData, float ratio)
        {
            using var img = Image.Load<Bgra32>(imageData);
            var cropSize = new Size((int)(img.Width * ratio), (int)(img.Height * ratio));
            img.Mutate(x => x.Crop(new Rectangle(
                (img.Width - cropSize.Width) / 2,
                (img.Height - cropSize.Height) / 2,
                cropSize.Width,
                cropSize.Height
            )));
            return GetImageBytes(img);
        }

        // 缩放攻击
        public static byte[] ApplyScaling(byte[] imageData, float scaleFactor)
        {
            using var img = Image.Load<Bgra32>(imageData);
            var newSize = new Size((int)(img.Width * scaleFactor), (int)(img.Height * scaleFactor));
            //img.Mutate(x => x.Resize(newSize, new NearestNeighborResampler()));
            // 正确写法（先指定重采样器）
            img.Mutate(x => x.Resize(new ResizeOptions
            {
                Size = newSize,
                Sampler = new LanczosResampler(), // 更高质量的重采样器
                Mode = ResizeMode.Stretch // 根据需求选择模式
            }));
            return GetImageBytes(img);
        }

        private static byte[] GetImageBytes(Image<Bgra32> img)
        {
            using var ms = new MemoryStream();
            img.SaveAsJpeg(ms);
            return ms.ToArray();
        }
    }
    #endregion


    public static class TestTools
    {
        public static byte[] ResizeImage(byte[] imageData, double scale)
        {
            using var image = Image.Load<Bgra32>(imageData);
            int newWidth = (int)(image.Width * scale);
            int newHeight = (int)(image.Height * scale);

            image.Mutate(ctx => ctx.Resize(newWidth, newHeight, new NearestNeighborResampler()));

            using var ms = new MemoryStream();
            image.SaveAsJpeg(ms);
            return ms.ToArray();
        }

        // 新增中心裁剪方法
        public static byte[] CropCenter(byte[] imageData, double retainRatio = 0.5)
        {
            using var image = Image.Load<Bgra32>(imageData);
            int cropWidth = (int)(image.Width * retainRatio);
            int cropHeight = (int)(image.Height * retainRatio);

            var cropRect = new Rectangle(
                (image.Width - cropWidth) / 2,
                (image.Height - cropHeight) / 2,
                cropWidth,
                cropHeight
            );

            using var croppedImage = image.Clone(ctx => ctx.Crop(cropRect));

            using var ms = new MemoryStream();
            croppedImage.SaveAsJpeg(ms);
            return ms.ToArray();
        }

        // 生成纯色测试图像
        public static byte[] GenerateSolidColorImage(int width, int height, byte r, byte g, byte b)
        {
            using var image = new Image<Bgra32>(width, height);
            image.Mutate(ctx => ctx.BackgroundColor(new Bgra32(r, g, b, 255)));

            using var ms = new MemoryStream();
            image.SaveAsPng(ms);
            return ms.ToArray();
        }

        // 生成棋盘格图像
        public static byte[] GenerateCheckerboard(int width, int height, int blockSize = 16)
        {
            using var image = new Image<Bgra32>(width, height);
            image.ProcessPixelRows(accessor =>
            {
                for (int y = 0; y < height; y++)
                {
                    Span<Bgra32> row = accessor.GetRowSpan(y);
                    bool yBlock = (y / blockSize) % 2 == 0;

                    for (int x = 0; x < width; x++)
                    {
                        bool xBlock = (x / blockSize) % 2 == 0;
                        row[x] = (xBlock ^ yBlock) ?
                            new Bgra32(255, 255, 255, 255) :
                            new Bgra32(0, 0, 0, 255);
                    }
                }
            });

            using var ms = new MemoryStream();
            image.SaveAsPng(ms);
            return ms.ToArray();
        }

        // 计算PSNR
        public static double CalculatePsnr(byte[] original, byte[] processed)
        {
            using var origImg = Image.Load<Bgra32>(original);
            using var procImg = Image.Load<Bgra32>(processed);

            double mse = 0;
            origImg.ProcessPixelRows(procImg, (origAccessor, procAccessor) =>
            {
                for (int y = 0; y < origAccessor.Height; y++)
                {
                    Span<Bgra32> origRow = origAccessor.GetRowSpan(y);
                    Span<Bgra32> procRow = procAccessor.GetRowSpan(y);

                    for (int x = 0; x < origRow.Length; x++)
                    {
                        mse += Math.Pow(origRow[x].R - procRow[x].R, 2);
                        mse += Math.Pow(origRow[x].G - procRow[x].G, 2);
                        mse += Math.Pow(origRow[x].B - procRow[x].B, 2);
                    }
                }
            });

            mse /= (origImg.Width * origImg.Height * 3);
            return 10 * Math.Log10(255 * 255 / mse);
        }

        public static void ValidateColorConversion()
        {
            const int size = 513;
            {
                // 1. 生成纯灰色测试图像

                byte[] grayImage = GenerateSolidColorImage(size, size, 128, 128, 128);

                // 2. 转换到YUV空间
                using var original = Image.Load<Bgra32>(grayImage);
                YuvData yuv = ColorConverter.RgbToYuv(original);

                // 3. 验证YUV分量
                bool isGrayValid = ValidateYuvComponents(yuv);
                Console.WriteLine($"YUV分量验证结果: {isGrayValid}");

                // 4. 转换回RGB
                Image<Bgra32> reconstructed = ColorConverter.YuvToRgb(yuv);

                // 5. 比较原始与重建图像
                double psnr = CalculatePsnr(grayImage, SaveImage(reconstructed));
                Console.WriteLine($"PSNR: {psnr:F2}dB (应接近无穷大)");
                Console.WriteLine($"像素差异: {ComparePixels(original, reconstructed)}");
            }
            {
                // 纯黑测试
                byte[] blackImage = TestTools.GenerateSolidColorImage(size, size, 0, 0, 0);
                YuvData blackYuv = ColorConverter.RgbToYuv(Image.Load<Bgra32>(blackImage));
                // 理论值: Y=0, U=0, V=0

                // 纯白测试
                byte[] whiteImage = TestTools.GenerateSolidColorImage(size, size, 255, 255, 255);
                YuvData whiteYuv = ColorConverter.RgbToYuv(Image.Load<Bgra32>(whiteImage));
            }
            {
                byte[] whiteImage = TestTools.GenerateSolidColorImage(size, size, 255, 255, 255);

                // 转换为YUV
                using var image = Image.Load<Bgra32>(whiteImage);
                YuvData yuv = ColorConverter.RgbToYuv(image);

                // 验证YUV分量
                const double tolerance = 1e-4;
                bool isValid = true;

                for (int y = 0; y < yuv.Height; y++)
                {
                    for (int x = 0; x < yuv.Width; x++)
                    {
                        if (Math.Abs(yuv.Y[x, y] - 1.0) > tolerance ||
                            Math.Abs(yuv.U[x, y]) > tolerance ||
                            Math.Abs(yuv.V[x, y]) > tolerance)
                        {
                            isValid = false;
                            break;
                        }
                    }
                }

                Console.WriteLine($"纯白测试验证结果: {isValid}");
            }
            {
                byte[] redImage = TestTools.GenerateSolidColorImage(size, size, 255, 0, 0);

                // 转换到YUV并立即转回RGB
                using var original = Image.Load<Bgra32>(redImage);
                YuvData yuv = ColorConverter.RgbToYuv(original);
                Image<Bgra32> reconstructed = ColorConverter.YuvToRgb(yuv);

                // 保存重建后的图像
                reconstructed.SaveAsPng("reconstructed_red.png");
            }
        }

        public static void ValidateDctIdct()
        {
            // 生成8x8测试块（灰度值128）
            const int N = 8;
            double[,] original = new double[N, N];
            for (int i = 0; i < N; i++)
                for (int j = 0; j < N; j++)
                    original[i, j] = 128.0;

            // 执行DCT+IDCT
            double[,] processed = (double[,])original.Clone();
            DctTransformer.Dct(processed);
            DctTransformer.Idct(processed);

            // 计算最大误差
            double maxError = 0;
            for (int i = 0; i < N; i++)
            {
                for (int j = 0; j < N; j++)
                {
                    double error = Math.Abs(original[i, j] - processed[i, j]);
                    maxError = Math.Max(maxError, error);
                }
            }

            Console.WriteLine($"DCT-IDCT最大误差: {maxError:F6}");
            Console.WriteLine($"测试结果: {(maxError < 1e-12 ? "通过" : "失败")}");
        }

        private static bool ValidateYuvComponents(YuvData yuv)
        {
            const double yTolerance = 1e-5;   // Y分量误差允许范围
            const double uvTolerance = 1e-4;  // UV分量误差允许范围

            for (int y = 0; y < yuv.Height; y++)
            {
                for (int x = 0; x < yuv.Width; x++)
                {
                    // 验证Y分量（理论值0.501960784）
                    double expectedY = 0.299 * (128 / 255.0) + 0.587 * (128 / 255.0) + 0.114 * (128 / 255.0);
                    if (Math.Abs(yuv.Y[x, y] - expectedY) > yTolerance) return false;

                    // 验证UV分量（理论值0）
                    if (Math.Abs(yuv.U[x, y]) > uvTolerance) return false;
                    if (Math.Abs(yuv.V[x, y]) > uvTolerance) return false;
                }
            }
            return true;
        }

        private static byte[] SaveImage(Image<Bgra32> image)
        {
            using var ms = new MemoryStream();
            image.SaveAsPng(ms);
            return ms.ToArray();
        }

        private static string ComparePixels(Image<Bgra32> orig, Image<Bgra32> reconstructed)
        {
            int diffCount = 0;
            orig.ProcessPixelRows(reconstructed, (origAccessor, recAccessor) =>
            {
                for (int y = 0; y < origAccessor.Height; y++)
                {
                    Span<Bgra32> origRow = origAccessor.GetRowSpan(y);
                    Span<Bgra32> recRow = recAccessor.GetRowSpan(y);

                    for (int x = 0; x < origRow.Length; x++)
                    {
                        if (origRow[x] != recRow[x]) diffCount++;
                    }
                }
            });
            return diffCount == 0 ? "完全匹配" : $"{diffCount} 个像素差异";
        }

        public static void FullValidationTest()
        {
            // 生成测试图像
            byte[] original = TestTools.GenerateCheckerboard(512, 512);

            // 转换处理流程
            YuvData yuv = ColorConverter.RgbToYuv(Image.Load<Bgra32>(original));
            ProcessAllBlocks(yuv); // 执行DCT+IDCT但不修改系数
            Image<Bgra32> output = ColorConverter.YuvToRgb(yuv);

            // 质量验证
            double psnr = TestTools.CalculatePsnr(original, SaveImage(output));
            Console.WriteLine($"PSNR值: {psnr:F2}dB"); // 应大于60dB

            // 像素级对比
            string diffCount = TestTools.ComparePixels(Image.Load<Bgra32>(original), output);
            Console.WriteLine($"差异像素数: {diffCount}"); // 应为0
        }

        private static void ProcessAllBlocks(YuvData yuv)
        {
            for (int y = 0; y < yuv.Height; y += 8)
            {
                for (int x = 0; x < yuv.Width; x += 8)
                {
                    double[,] block = WatermarkCore.GetBlock(yuv.Y, x, y, 8);
                    DctTransformer.Dct(block);
                    DctTransformer.Idct(block);
                    WatermarkCore.SetBlock(yuv.Y, block, x, y);
                }
            }
        }

        //public static void TestSpiralOrder(int width, int height)
        //{
        //    int blockSize = 8;
        //    int wBlocks = (width + blockSize - 1) / blockSize;
        //    int hBlocks = (height + blockSize - 1) / blockSize;

        //    var order = WatermarkCore.GenerateBlockOrder(wBlocks, hBlocks);
        //    Console.WriteLine($"{width}x{height} => 块数:{wBlocks}x{hBlocks} 实际遍历:{order.Count} 应遍历:{wBlocks * hBlocks}");
        //}

        public static byte[] ConvertToJpeg(byte[] imageData, int quality = 75)
        {
            using var image = Image.Load<Bgra32>(imageData);
            using var ms = new MemoryStream();
            image.SaveAsJpeg(ms, new JpegEncoder
            {
                Quality = quality,
                ColorType = JpegEncodingColor.YCbCrRatio420 // 使用4:2:0采样
            });
            return ms.ToArray();
        }

        // 添加旋转攻击模拟
        public static byte[] RotateImage(byte[] imageData, float degrees)
        {
            using var image = Image.Load<Bgra32>(imageData);
            image.Mutate(ctx => ctx.Rotate(degrees));
            using var ms = new MemoryStream();
            image.SaveAsPng(ms);
            return ms.ToArray();
        }



        #region 抗噪测试
        public static void TestNoiseResistance()
        {
            // 1. 准备测试数据
            string originalImagePath = @"D:\ywd\work\ncs\新水印的尝试\MyWatermark\gitee\pic\3.png";
            string watermarkMsg = "TEST123";
            byte[] originalBytes = File.ReadAllBytes(originalImagePath);

            // 2. 嵌入水印
            var watermarkBits = WatermarkCore.TextToBinaryWithHeader(watermarkMsg);
            byte[] watermarked = WatermarkCore.Embed(watermarkBits, originalBytes);

            // 3. 定义测试参数
            var testCases = new[]
            {
        new { Type = "Gaussian", Params = new object[] { 5.0 } },
        new { Type = "Gaussian", Params = new object[] { 10.0 } },
        new { Type = "Gaussian", Params = new object[] { 20.0 } },
        new { Type = "JPEG", Params = new object[] { 75 } },
        new { Type = "JPEG", Params = new object[] { 50 } }
    };

            // 4. 执行测试
            foreach (var testCase in testCases)
            {
                byte[] attackedImage = testCase.Type switch
                {
                    "Gaussian" => NoiseTestTools.AddGaussianNoise(watermarked, (double)testCase.Params[0]),
                    "JPEG" => NoiseTestTools.AddJpegCompression(watermarked, (int)testCase.Params[0]),
                    _ => watermarked
                };


                //string path = @$"D:\ywd\work\ncs\新水印的尝试\MyWatermark\gitee\pic\{testCase.Type.ToString()}{testCase.Params[0].ToString()}.png";
                //File.WriteAllBytes(path, attackedImage);

                // 5. 提取水印
                BitArray extracted = WatermarkCore.Extract(attackedImage);
                string result = WatermarkCore.BinaryToTextWithHeader(extracted);

                // 6. 计算指标
                int errorBits = CalculateErrorBits(watermarkBits, extracted);
                double ber = (double)errorBits / watermarkBits.Count;
                double psnr = TestTools.CalculatePsnr(watermarked, attackedImage);

                // 7. 输出结果
                Console.WriteLine($"""
            [{testCase.Type} {testCase.Params[0]}]
            原始水印: {watermarkMsg}
            提取结果: {result}
            误码率: {ber:P2}
            PSNR: {psnr:F2} dB
            ------------------------------
            """);
            }
        }

        private static int CalculateErrorBits(List<bool> original, BitArray extracted)
        {
            int errors = 0;
            for (int i = 0; i < Math.Min(original.Count, extracted.Length); i++)
            {
                if (original[i] != extracted[i]) errors++;
            }
            return errors;
        }
        #endregion


        #region 几何攻击测试
        public static void TestGeometricResistance()
        {
            // 1. 准备测试数据
            const string originalImagePath = @"D:\ywd\work\ncs\新水印的尝试\MyWatermark\gitee\pic\3.png";
            const string watermarkMsg = "GEOTEST123";
            var originalBytes = File.ReadAllBytes(originalImagePath);

            // 2. 嵌入水印
            var watermarkBits = WatermarkCore.TextToBinaryWithHeader(watermarkMsg);
            var watermarked = WatermarkCore.Embed(watermarkBits, originalBytes);

            // 3. 定义测试矩阵
            var testCases = new[]
            {
        new { Attack = "Rotation", Params = new object[] { 5f } },   // 5度旋转
        new { Attack = "Rotation", Params = new object[] { -10f } },// 逆时针10度
        new { Attack = "Crop", Params = new object[] { 0.8f } },     // 裁切20%
        new { Attack = "Crop", Params = new object[] { 0.6f } },      // 裁切40%
        new { Attack = "Scale", Params = new object[] { 0.9f } },    // 缩小10%
        new { Attack = "Scale", Params = new object[] { 1.2f } },    // 放大20%
    };

            // 4. 执行测试流程
            foreach (var testCase in testCases)
            {
                byte[] attackedImage = testCase.Attack switch
                {
                    "Rotation" => GeometricAttackTools.ApplyRotation(watermarked, (float)testCase.Params[0]),
                    "Crop" => GeometricAttackTools.ApplyCenterCrop(watermarked, (float)testCase.Params[0]),
                    "Scale" => GeometricAttackTools.ApplyScaling(watermarked, (float)testCase.Params[0]),
                    _ => watermarked
                };

                // 5. 提取水印（带几何校正）
                //BitArray extracted = ExtractWithGeometricCorrection(attackedImage, watermarked.Length);
                // 获取原始图像尺寸
                var img = Image.Load<Bgra32>(originalBytes);
                var originalSize = new Size(img.Width, img.Height);

                // 传递正确尺寸对象
                BitArray extracted = ExtractWithGeometricCorrection(attackedImage, originalSize);
                string result = WatermarkCore.BinaryToTextWithHeader(extracted);

                // 6. 计算评估指标
                int errorBits = CalculateErrorBits(watermarkBits, extracted);
                double ber = (double)errorBits / watermarkBits.Count;

                Console.WriteLine($"""
            [{testCase.Attack} {testCase.Params[0]}]
            提取结果: {result.PadRight(watermarkMsg.Length)}
            误码率: {ber:P2}
            可用性: {(result.Contains(watermarkMsg) ? "✔" : "❌")}
            ------------------------------
            """);
            }
        }

        // 带几何校正的提取方法
        private static BitArray ExtractWithGeometricCorrection(byte[] attackedImage, Size originalSize)
        {
            using var img = Image.Load<Bgra32>(attackedImage);

            // 计算相对尺寸差异
            double widthDiff = Math.Abs(img.Width - originalSize.Width) / (double)originalSize.Width;
            double heightDiff = Math.Abs(img.Height - originalSize.Height) / (double)originalSize.Height;

            // 设置动态阈值（1%变化）
            const double threshold = 0.01;

            if (widthDiff > threshold || heightDiff > threshold)
            {
                img.Mutate(x => x.Resize(new ResizeOptions
                {
                    Size = originalSize,
                    Sampler = new LanczosResampler(),
                    Mode = ResizeMode.Max // 保持比例缩放
                }));
            }

            // 2. 旋转检测（需要实现实际检测算法）
            float detectedAngle = DetectRotationAngle(img); // 需要实现角度检测
            if (Math.Abs(detectedAngle) > 1)
            {
                img.Mutate(x => x.Rotate(-detectedAngle));
            }

            return WatermarkCore.Extract(NoiseTestTools.GetImageBytes(img));
        }

        // 简单角度检测（示例：需要替换为实际算法）
        private static float DetectRotationAngle(Image<Bgra32> img)
        {
            // 实现实际的角度检测逻辑（如Hough变换、EXIF读取等）
            return 0f; // 示例返回0度
        }
        #endregion


    }
}
